package com.home.auto_navigation.common;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.pagefactory.DefaultElementLocatorFactory;
import org.openqa.selenium.support.pagefactory.DefaultFieldDecorator;
import org.openqa.selenium.support.pagefactory.ElementLocator;

import com.home.auto_navigation.ui.controllers.Button;

public class AutoNavigationFileDecorator extends DefaultFieldDecorator {

	public AutoNavigationFileDecorator(SearchContext searchContext) {
		super(new DefaultElementLocatorFactory(searchContext));
	}

	@Override
	public Object decorate(ClassLoader loader, Field field) {
		Class<?> clazz = null;
		ElementLocator locator = factory.createLocator(field);
		if (locator == null) {
			return null;
		}

		if (WebElement.class.isAssignableFrom(field.getType())) {
			return proxyForLocator(loader, locator);
		} else if (Button.class.isAssignableFrom(clazz = field.getType())) {
			WebElement webElement = proxyForLocator(loader, locator);
			return createElement(clazz, field.getName(), webElement);
		} else if (List.class.isAssignableFrom(field.getType())) {
            clazz = (Class<?>) ((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0];
            List<WebElement> list = proxyForListLocator(loader, locator);
            return createListOfElements(clazz, field.getName(), list);
        } else {
			return null;
		}
	}
	
    @SuppressWarnings("unchecked")
    private <T> T createListOfElements(Class<?> clazz, String fieldName, List<WebElement> listOfWebElements) {
        List<T> list = new ArrayList<T>();
        try {
           for(WebElement webElement: listOfWebElements){
               T element = (T) clazz.getDeclaredConstructor(WebElement.class, String.class).newInstance(webElement, fieldName);
               list.add(element);   
           } 
        } catch (Exception e) {
            System.err.println("constructor with 'WebElement and String' in class" + clazz + "does not exist");
            e.printStackTrace();
        } 
      
        return (T) list;
    }
	
	@SuppressWarnings("unchecked")
	private <T> T createElement(final Class<?> clazz, String fieldName, final WebElement webElement) {
		Object button = null;
		try {
			button = clazz.getDeclaredConstructor(WebElement.class, String.class).newInstance(webElement, fieldName);
		} catch (Exception e) {
			System.err.println("constructor with 'WebElement and String' in class" + clazz + "does not exist");
			e.printStackTrace();
		} 
		return (T) button;
	}
	
}
